/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.idea.utils.sfo;


import designersfo.Root;
import idea.model.dbmanager.QueryManager;
import idea.model.dbmanager.SfoEnum;
import idea.model.qnrlibrary.QuestionTitle;
import java.io.File;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Iterator;
import java.util.List;
import javax.swing.ImageIcon;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.codec.binary.Base64;
import org.openide.util.Exceptions;
import sfoutils.SFOUtils;


/**
 *
 * @author renke002
 */
public class SFODocManager
{

    /**
     *
     */
    private String currQuestID = null;
    /**
     * Root element for the SFO XML File.
     */
    private Root docRoot = null;
    /**
     * ER add JAXB context to set up marshalers
     */
    private JAXBContext jc = null;
    /**
     * the non ASCII characters that begin an SFO document
     */
    private char[] savedNonAscii = null;


    /**
     * xtor
     */
    public SFODocManager( String sfoFileName )
    {
        /**
         * Ed add set up the JAXB Context
         */
        try
        {
            jc = JAXBContext.newInstance( "designersfo" );
        } catch ( Exception e )
        {
            Exceptions.printStackTrace( e );
        }

        try
        {
            this.docRoot = this.loadSFOFile( sfoFileName );
        } catch ( JAXBException ex )
        {
            Exceptions.printStackTrace( ex );
        }

    }


    /**
     *
     * @param sfo
     * @param questId
     * @param savedNonAscii
     * @throws JAXBException
     */
    public SFODocManager( String sfo , String questId , char[] savedNonAscii ) throws JAXBException
    {
        try
        {
            jc = JAXBContext.newInstance( "designersfo" );
        } catch ( Exception e )
        {
            Exceptions.printStackTrace( e );
        }
        this.loadSFOString( sfo , questId , savedNonAscii );
    }


    /**
     *
     * @param sfoFileName - full name of the SFO file to load.
     * @return designersfo.Root - Root element of the xml tree in the file.
     * @throws JAXBException
     */
//    public static Root loadDesigner( String sfoFileName ) throws JAXBException
//    {
//        JAXBContext jc = JAXBContext.newInstance( "designersfo" );
//        Unmarshaller um = jc.createUnmarshaller();
//        File sfoFile = new File( sfoFileName );
//        return (Root) um.unmarshal( sfoFile );
//    }
    /**
     * unmarshalls the test file. no longer used.
     *
     * @return
     * @throws JAXBException
     */
//    public Root loadSFOFile() throws JAXBException
//    {
//        //JAXBContext jc = JAXBContext.newInstance( "designersfo" );
//        Unmarshaller um = jc.createUnmarshaller();
//        return (Root) um.unmarshal( new File( "massimo.xml" ) );
//    }
    /**
     *
     * @param sfo
     * @return
     * @throws JAXBException
     */
    private void loadSFOString( String sfo , String questID , char[] savedNonAscii ) throws JAXBException
    {
        Unmarshaller um = jc.createUnmarshaller();
        sfo = "<?xml version=\"1.0\"?>" + sfo;
        currQuestID = questID;
        this.savedNonAscii = savedNonAscii;

        this.docRoot = (Root) um.unmarshal( new StreamSource( new StringReader( sfo ) ) );
    }


    /**
     * more generic, unmarshalls (JAXB style) a given SFO xml file.
     *
     * @param sfoFile
     * @return the root object containing the entire tree.
     * @throws JAXBException
     */
    public Root loadSFOFile( String sfoFile ) throws JAXBException
    {
        //JAXBContext jc = JAXBContext.newInstance( "designersfo" );
        Unmarshaller um = jc.createUnmarshaller();
        return (Root) um.unmarshal( new File( sfoFile ) );
    }


    /**
     * Save a compressed, encoded SFO string to the DB Marshall the DocRoot to
     * a string.
     *
     * @throws JAXBException
     */
    public void saveSFO() throws JAXBException
    {
        this.saveSFO( this.docRoot );
    }


    /**
     *
     * @param root
     * @throws JAXBException
     */
    public void saveSFO( Root root ) throws JAXBException
    {
        boolean testing = true;
        // get docRoot ready for DB
        StringWriter writer = new StringWriter();

        String questID = currQuestID;
        final int COMP_BYTE_LEN = 30000;

        //byte[] compressed = new byte[ 2000 ];
        byte[] compressed = new byte[ COMP_BYTE_LEN ];
        String encodedStr;

        Marshaller m = jc.createMarshaller();
        m.marshal( root , writer );
        String sfo = writer.toString();
        sfo = sfo.replaceFirst( "\\<\\?.*\\?\\>" , "" ); // First remove XML header
        int len = sfo.length();
        System.out.println( "SFO to save, len " + len + ", /" + sfo + "/" );
        if ( savedNonAscii != null )
        {
            // Add the two saved off nonAscii characters
            StringBuilder sb = new StringBuilder();
            for ( int i = 0; i < savedNonAscii.length; i++ )
            {
                sb = sb.append( savedNonAscii[i] );
            }
            sb = sb.append( sfo );
            sfo = sb.toString();
        }
        int sfolen = sfo.length();
        System.out.println( "Root string for questID " + currQuestID + ": (len " + sfolen + ") /" + sfo + "/" );
        SFOUtils su = new SFOUtils();
        int compLen = su.deflate( sfo , compressed );
        System.out.println( "Compressed len is " + compLen );
        if ( testing )
        {
            int reslen = su.inflate( compressed , COMP_BYTE_LEN );
            System.out.println( "Res len is " + reslen );
            String testSfo = su.getOutput();
            int testSfoLen = testSfo.length();
            System.out.println( "Test SFO len is " + testSfoLen + ", /" + testSfo + "/" );
        }

        encodedStr = Base64.encodeBase64String( compressed );
        System.out.println( "compressed and encoded (" + encodedStr.length() + " bytes):" );
        System.out.println( "to store in DB: /" + encodedStr + "/" );

        if ( testing )
        {
            su.setB64( new Base64() );
            su.setDecoded( su.getB64().decode( encodedStr ) );
            System.out.println( "decoded compressed len : " + su.getDecoded().toString().length() + ", /" + su.getDecoded().toString() + "/" );
        }

        // go get the QuestionTitle for this questId
        List<QuestionTitle> qts = QueryManager.getQT( questID );
        Iterator<QuestionTitle> qtit = qts.iterator();
        QuestionTitle qt = null;
        while ( qtit.hasNext() )
        {
            qt = qtit.next();
            break;  // there will only be one
        }

        QueryManager.updateSfoClob( SfoEnum.DESIGNER , encodedStr , qt );
    }


    /**
     * 
     * @return 
     */
    public ImageIcon getJpegImage()
    {
        ImageIcon image = null;
        if ( currQuestID != null )
        {
            List<QuestionTitle> qts = QueryManager.getQT( currQuestID );
            QuestionTitle qt = null;
            Iterator<QuestionTitle> qtit = qts.iterator();
            while ( qtit.hasNext() )
            {
                qt = qtit.next();
                break;
            }
            image = QueryManager.getJpegFromDB( qt );
        }
        return image;
    }


    /**
     *
     * @return a reference to the SFO's XML Document Root
     */
    public Root getDocRoot()
    {
        return this.docRoot;
    }

}
